#include "part2d_editor.h"
#include "part2d.h"

#include "ui/ui_manager.h"
#include "ui/ui_checkbox.h"
#include "ui/ui_dropdown.h"
#include "ui/ui_slider.h"

#include "gameflow/game_flow_manager.h"

#include "script/scripthelper.h"
#include "util/common_macros.h"
#include "util/filepath.h"
#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#endif // _ENABLE_LUABIND
using namespace part2d;

#include <cassert>

// =========================================================================================================================
// class P2DEdit_Container
//

P2DEdit_Container::P2DEdit_Container(P2DEdit* pEditor) : m_pEditor(pEditor),
	m_pParticle(NULL),
	m_Current(0),
	m_TriggerC(10)
{
	m_TriggerCounter.SetLimit(2.0f);
	m_TriggerCounter.SetCounter(-1);
}

P2DEdit_Container::~P2DEdit_Container()
{
	UTIL_SAFE_DELETE(m_pParticle);
}

void P2DEdit_Container::CreateParticle()
{
	UTIL_SAFE_DELETE(m_pParticle);
	m_pParticle = new Part2D();
}

void P2DEdit_Container::Setup(const math::Vec2& pos, const math::Vec2& size)
{
	m_Pos = pos;
	m_Size = size;
}

bool P2DEdit_Container::Tick(float dt)
{
	switch (m_pEditor->GetPreviewMode())
	{
	case P2DEdit::PREVIEW_LINE:
		for (int i = 0; i < m_pParticle->GroupC(); i++) {
			if (m_pParticle->GetGroup(i)->ShouldCreateParticle(dt))
			{
				m_pParticle->TriggerParticlesOnLine(m_Pos + math::Vec2(0.0f, 0.5f*m_Size.y + m_Offset.y),
													m_Pos + math::Vec2(m_Size.x, 0.5f*m_Size.y + m_Offset.y));
			}
		}
		break;
	case P2DEdit::PREVIEW_TRIGGER:
		m_TriggerCounter.Tick(dt);
		if (m_TriggerCounter.IsReady()) {
			for (int i = 0; i < m_TriggerC; i++)
				m_pParticle->TriggerParticles(m_Pos + (0.5f * m_Size) + m_Offset);
			m_TriggerCounter.Reset();
		}
		break;
	case P2DEdit::PREVIEW_DEFAULT:
	default:
		m_pParticle->TickCreation(dt, m_Pos + (0.5f * m_Size) + m_Offset, math::Vec2());
		break;
	}

	return m_pParticle->Tick(dt);
}

void P2DEdit_Container::Render(const math::Vec2& Min, const math::Vec2& Max)
{
	m_pParticle->Render(math::Vec2(), 1, Min, Max);
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, const std::string& szData)
{
	switch (cmd)
	{
	case CMD_LOAD:			CreateParticle(); m_pParticle->Load(szData); m_FileName = szData; m_Current = 0; return 1;
	case CMD_SAVE:			m_pParticle->Save(szData); m_FileName = szData; return 1;
	}

	if (m_pParticle->GroupC() <= m_Current) return 0;

	switch (cmd)
	{
	case CMD_IMAGE:			m_pParticle->GetGroup(m_Current)->SetImage(szData); return 1;
	}

	return 0;
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, CONTAINER_VAL Data)
{
	switch (cmd)
	{
	case CMD_GROUP:			m_Current = Data.iData; return m_Current;
	case CMD_ADDGROUP:		m_pParticle->CreateGroup(); return m_pParticle->GroupC();
	}

	if (m_pParticle->GroupC() <= m_Current) return 0;

	switch (cmd)
	{
	case CMD_DELGROUP:		m_pParticle->DeleteGroup(m_Current); return m_pParticle->GroupC();
	case CMD_MAXC:			m_pParticle->GetGroup(m_Current)->SetMaxC(Data.iData); return 1;
	case CMD_ADDITIVE:		m_pParticle->GetGroup(m_Current)->SetAdditive(Data.dwData ? true : false); return 1;
	case CMD_LOCKRECT:		m_pParticle->GetGroup(m_Current)->SetLockRect(Data.dwData ? true : false); return 1;
	case CMD_STRETCHSPEED:	m_pParticle->GetGroup(m_Current)->SetStretchSpeed(Data.fData); return 1;
	case CMD_MINSPEEDMAG:	if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetInitialSpeed(pGroup->GetMinSpeed(),
														pGroup->GetMaxSpeed(),
														Data.fData);
							} return 1;
	case CMD_GENRATE:		m_pParticle->GetGroup(m_Current)->SetGenRate(Data.fData); return 1;
	case CMD_CLEARCOLOR:	m_pParticle->GetGroup(m_Current)->ClearColors(); return 1;
	}

	return 0;
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, const math::Vec2& vData)
{
	if (m_pParticle->GroupC() <= m_Current) return 0;

	switch (cmd)
	{
	case CMD_FUZZYBIRTH:	m_pParticle->GetGroup(m_Current)->SetFuzzyBirth(vData); return 1;
	case CMD_SIZEFROM_MIN:	if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetSize(vData,
												pGroup->GetSizeFromMax(),
												pGroup->GetSizeToMin(),
												pGroup->GetSizeToMax());
							}; return 1;
	case CMD_SIZEFROM_MAX:	if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetSize(pGroup->GetSizeFromMin(),
												vData,
												pGroup->GetSizeToMin(),
												pGroup->GetSizeToMax());
							}; return 1;
	case CMD_SIZETO_MIN:	if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetSize(pGroup->GetSizeFromMin(),
												pGroup->GetSizeFromMax(),
												vData,
												pGroup->GetSizeToMax());
							}; return 1;
	case CMD_SIZETO_MAX:	if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetSize(pGroup->GetSizeFromMin(),
												pGroup->GetSizeFromMax(),
												pGroup->GetSizeToMin(),
												vData);
							}; return 1;
	case CMD_LIFESPAN:		m_pParticle->GetGroup(m_Current)->SetLifespan(vData); return 1;
	case CMD_MINSPEED:		if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetInitialSpeed(vData,
														pGroup->GetMaxSpeed(),
														pGroup->GetMinSpeedMag());
							} return 1;
	case CMD_MAXSPEED:		if (PartGroup* pGroup = m_pParticle->GetGroup(m_Current)) {
								pGroup->SetInitialSpeed(pGroup->GetMinSpeed(),
														vData,
														pGroup->GetMinSpeedMag());
							} return 1;
	}

	return 0;
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, const math::Vec4& vData)
{
	if (m_pParticle->GroupC() <= m_Current) return 0;

	switch (cmd)
	{
	case CMD_ADDCOLOR:		m_pParticle->GetGroup(m_Current)->AddColor(vData); return 1;
	}

	return 0;
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd)
{
	CONTAINER_VAL Data;
	Data.dwData = 0;
	return SetCmd(cmd, Data);
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, int iData)
{
	CONTAINER_VAL Data;
	Data.iData = iData;
	return SetCmd(cmd, Data);
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, float fData)
{
	CONTAINER_VAL Data;
	Data.fData = fData;
	return SetCmd(cmd, Data);
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, unsigned long dwData)
{
	CONTAINER_VAL Data;
	Data.dwData = dwData;
	return SetCmd(cmd, Data);
}

int P2DEdit_Container::SetCmd(const CONTAINER_CMD& cmd, bool bData)
{
	CONTAINER_VAL Data;
	Data.dwData = bData ? 1 : 0;
	return SetCmd(cmd, Data);
}

bool P2DEdit_Container::GetCmd(const CONTAINER_CMD& cmd, CONTAINER_VAL& val)
{
	switch (cmd)
	{
	case CMD_GROUPCOUNT:	val.iData = m_pParticle->GroupC(); return true;
	}

	if (m_pParticle->GroupC() <= m_Current) return false;

	switch (cmd)
	{
	case CMD_GROUP:			val.iData = m_Current; return true;
	case CMD_MAXC:			val.iData = m_pParticle->GetGroup(m_Current)->GetMaxC(); return true;
	case CMD_ADDITIVE:		val.dwData = m_pParticle->GetGroup(m_Current)->GetAdditive() ? 1 : 0; return true;
	case CMD_LOCKRECT:		val.dwData = m_pParticle->GetGroup(m_Current)->GetLockRect() ? 1 : 0; return true;
	case CMD_STRETCHSPEED:	val.fData = m_pParticle->GetGroup(m_Current)->GetStretchSpeed(); return true;
	case CMD_MINSPEEDMAG:	val.fData = m_pParticle->GetGroup(m_Current)->GetMinSpeedMag(); return true;
	case CMD_GENRATE:		val.fData = m_pParticle->GetGroup(m_Current)->GetGenRate(); return true;
	}

	return false;
}

bool P2DEdit_Container::GetCmd(const CONTAINER_CMD& cmd, std::string& val)
{
	if (m_pParticle->GroupC() <= m_Current) return false;

	switch (cmd)
	{
	case CMD_IMAGE:			val = m_pParticle->GetGroup(m_Current)->GetImage(); return true;
	}

	return false;
}

bool P2DEdit_Container::GetCmd(const CONTAINER_CMD& cmd, math::Vec2& val)
{
	if (m_pParticle->GroupC() <= m_Current) return false;

	switch (cmd)
	{
	case CMD_FUZZYBIRTH:	val = m_pParticle->GetGroup(m_Current)->GetFuzzyBirth(); return true;
	case CMD_SIZEFROM_MIN:	val = m_pParticle->GetGroup(m_Current)->GetSizeFromMin(); return true;
	case CMD_SIZEFROM_MAX:	val = m_pParticle->GetGroup(m_Current)->GetSizeFromMax(); return true;
	case CMD_SIZETO_MIN:	val = m_pParticle->GetGroup(m_Current)->GetSizeToMin(); return true;
	case CMD_SIZETO_MAX:	val = m_pParticle->GetGroup(m_Current)->GetSizeToMax(); return true;
	case CMD_LIFESPAN:		val = m_pParticle->GetGroup(m_Current)->GetLifespan(); return true;
	case CMD_MINSPEED:		val = m_pParticle->GetGroup(m_Current)->GetMinSpeed(); return true;
	case CMD_MAXSPEED:		val = m_pParticle->GetGroup(m_Current)->GetMaxSpeed(); return true;
	}

	return false;
}


// =========================================================================================================================
// class P2DEdit
//

std::string P2DEdit::m_StateName = "p2dedit_state";

P2DEdit::P2DEdit(camera::FbCamera* pCamera, const std::string& BasePanel, const std::string& EnterScript, const std::string& ExitScript) :
	gameflow::UIState(pCamera, BasePanel, EnterScript, ExitScript),
	m_pContainer(NULL),
	m_pPanel(NULL),
	m_PreviewMode(PREVIEW_DEFAULT)
{
	m_PreviewExtents[0] = math::Vec2(0.0f, 0.0f);
	m_PreviewExtents[1] = math::Vec2(1.0f, 1.0f);
}

P2DEdit::~P2DEdit()
{
	UTIL_SAFE_DELETE(m_pContainer);
}

void P2DEdit::CreateContainer()
{
	UTIL_SAFE_DELETE(m_pContainer);
	m_pContainer = new P2DEdit_Container(this);
	m_pContainer->CreateParticle();
}

void P2DEdit::InitWidgets()
{
	// override this function for custom ui
	m_Widgets.Additive = "additive_box";
	m_Widgets.ColorA = "color_alpha";
	m_Widgets.ColorB = "color_blue";
	m_Widgets.ColorG = "color_green";
	m_Widgets.ColorPreview = "preview_color";
	m_Widgets.ColorR = "color_red";
	m_Widgets.FileName = "file_name";
	m_Widgets.FuzzyBirthMax = "fuzzybirth_max";
	m_Widgets.FuzzyBirthMin = "fuzzybirth_min";
	m_Widgets.GenRate = "gen_rate";
	m_Widgets.GroupList = "groups_list";
	m_Widgets.ImageName = "image_name";
	m_Widgets.LifespanMax = "lifespan_max";
	m_Widgets.LifespanMin = "lifespan_min";
	m_Widgets.LockRect = "lockrect_box";
	m_Widgets.MaxCount = "max_count";
	m_Widgets.MaxSpeedX = "max_speed_x";
	m_Widgets.MaxSpeedY = "max_speed_y";
	m_Widgets.MinSpeedMag = "min_speed_mag";
	m_Widgets.MinSpeedX = "min_speed_x";
	m_Widgets.MinSpeedY = "min_speed_y";
	m_Widgets.PreviewPane = "preview_pane";
	m_Widgets.SizeFromMaxX = "sizefrom_max_x";
	m_Widgets.SizeFromMaxY = "sizefrom_max_y";
	m_Widgets.SizeFromMinX = "sizefrom_min_x";
	m_Widgets.SizeFromMinY = "sizefrom_min_y";
	m_Widgets.SizeToMaxX = "sizeto_max_x";
	m_Widgets.SizeToMaxY = "sizeto_max_y";
	m_Widgets.SizeToMinX = "sizeto_min_x";
	m_Widgets.SizeToMinY = "sizeto_min_y";
	m_Widgets.StretchSpeed = "stretch_speed";
}

bool P2DEdit::OnEnter()
{
	gameflow::UIState::OnEnter();

	// custom enter
	CreateContainer();
	RefreshUI();
	return true;
}

bool P2DEdit::OnExit()
{
	gameflow::UIState::OnExit();

	// custom exit
	UTIL_SAFE_DELETE(m_pContainer);
	return true;
}

bool P2DEdit::PreRender()
{
	gameflow::UIState::PreRender();
	return true;
}

bool P2DEdit::PostRender()
{
	gameflow::UIState::PostRender();

	if (m_pContainer) m_pContainer->Render(m_PreviewExtents[0], m_PreviewExtents[1]);
	return true;
}

bool P2DEdit::Tick(float dt)
{
	gameflow::UIState::Tick(dt);

	if (m_pContainer) m_pContainer->Tick(dt);
	return true;
}

void P2DEdit::RefreshUI()
{
	if (!m_pContainer) return;
	if (m_Panels.empty()) return;

	if (!m_pPanel) {
		m_pPanel = m_Panels[0];
		InitWidgets();
	}

	// custom refresh
	ui::UIWidget* pWidget = NULL;
	P2DEdit_Container::CONTAINER_VAL val;
	std::string szStr;
	char szData[256];
	math::Vec2 vec;

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.FileName)){
		pWidget->SetTextA(FilePath::GetFNameFromPath(m_pContainer->GetFileName()));
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.ImageName)) {
		if (m_pContainer->GetCmd(P2DEdit_Container::CMD_IMAGE, szStr))
			pWidget->SetTextA(szStr);
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.PreviewPane)) {
		m_PreviewExtents[0] = pWidget->GetPosition();
		m_PreviewExtents[1] = m_PreviewExtents[0] + pWidget->GetSize();
		m_pContainer->Setup(pWidget->GetPosition(), pWidget->GetSize());
		switch (m_PreviewMode)
		{
		case PREVIEW_LINE:		pWidget->SetTextA("preview[line]"); break;
		case PREVIEW_TRIGGER:	pWidget->SetTextA("preview[trigger]"); break;
		case PREVIEW_DEFAULT:
		default:				pWidget->SetTextA("preview[default]"); break;
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.GroupList)) {
		if (pWidget->GetType() == ui::UIWidget::WT_DROPDOWN)
		{
			ui::UIDropDown* pDropdown = (ui::UIDropDown*)pWidget;
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_GROUPCOUNT, val))
			{
				pDropdown->Clear();
				for (int i = 0; i < val.iData; i++) {
					sprintf(szData, "GROUP_%d", i+1);
					pDropdown->AddOption(szData);
				}

				if (m_pContainer->GetCmd(P2DEdit_Container::CMD_GROUP, val)) {
					pDropdown->SetCurrentOption(val.iData);
					pDropdown->SetTextA(pDropdown->GetSelectedText());
				}
			}
		}
	}
	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MaxCount)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_PreviewMode == PREVIEW_TRIGGER)
			{
				float f = float(m_pContainer->GetTriggerC() - MinTriggerCount() + 1) / float(MaxTriggerCount() - MinTriggerCount() + 1);
				((ui::UISlider*)pWidget)->SetSlider(f);
			}
			else
			{
				if (m_pContainer->GetCmd(P2DEdit_Container::CMD_MAXC, val))
				{
					float f = float(val.iData - MinCount() + 1) / float(MaxCount() - MinCount() + 1);
					((ui::UISlider*)pWidget)->SetSlider(f);
				}
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.Additive)) {
		if (pWidget->GetType() == ui::UIWidget::WT_CHECKBOX)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_ADDITIVE, val))
				((ui::UICheckBox*)pWidget)->SetChecked(val.dwData ? true : false);
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.LockRect)) {
		if (pWidget->GetType() == ui::UIWidget::WT_CHECKBOX)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_LOCKRECT, val))
				((ui::UICheckBox*)pWidget)->SetChecked(val.dwData ? true : false);
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.FuzzyBirthMin)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_FUZZYBIRTH, vec))
			{
				ExpandV(vec);
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.FuzzyBirthMax))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	
	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeFromMinX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_SIZEFROM_MIN, vec))
			{
				vec.x /= MaxSize();
				vec.y /= MaxSize();
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeFromMinY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeFromMaxX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_SIZEFROM_MAX, vec))
			{
				vec.x /= MaxSize();
				vec.y /= MaxSize();
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeFromMaxY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeToMinX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_SIZETO_MIN, vec))
			{
				vec.x /= MaxSize();
				vec.y /= MaxSize();
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeToMinY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeToMaxX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_SIZETO_MAX, vec))
			{
				vec.x /= MaxSize();
				vec.y /= MaxSize();
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.SizeToMaxY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.LifespanMin)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_LIFESPAN, vec))
			{
				vec.x /= MaxLife();
				vec.y /= MaxLife();
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.LifespanMax))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MinSpeedX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_MINSPEED, vec))
			{
				ExpandV(vec);
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MinSpeedY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MaxSpeedX)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_MAXSPEED, vec))
			{
				ExpandV(vec);
				((ui::UISlider*)pWidget)->SetSlider(vec.x);

				if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MaxSpeedY))
					if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
						((ui::UISlider*)pWidget)->SetSlider(vec.y);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.StretchSpeed)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_STRETCHSPEED, val))
				((ui::UISlider*)pWidget)->SetSlider(val.fData);
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.MinSpeedMag)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_MINSPEEDMAG, val))
			{
				float f = (val.fData < 0.0f) ? 0.0f : val.fData;
				((ui::UISlider*)pWidget)->SetSlider(f);
			}
		}
	}

	if (pWidget = m_pPanel->GetWidgetByName(m_Widgets.GenRate)) {
		if (pWidget->GetType() == ui::UIWidget::WT_SLIDER)
		{
			if (m_pContainer->GetCmd(P2DEdit_Container::CMD_GENRATE, val))
			{
				float f = val.fData;
				UTIL_CLAMP(f, (1.0f / MaxFreq()), 1.0f);
				f = 1.0f / (f * MaxFreq());
				((ui::UISlider*)pWidget)->SetSlider(f);
			}
		}
	}
}

static P2DEdit* GetP2DEdit()
{
	gameflow::GameFlowManager& Manager = gameflow::GameFlowManager::Instance();
	P2DEdit* pState = (P2DEdit*)Manager.GetStateByName(P2DEdit::m_StateName);
	assert(pState && "No valid Game state!");
	return pState;
}

void P2DEdit::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
	lua_State* L = _pScript->GetCState();

	luabind::module(L)
    [
	luabind::class_<P2DEdit>(P2DEdit::m_StateName.c_str())
		.def("LoadParticle",		&P2DEdit::LoadParticle)
		.def("SaveParticle",		&P2DEdit::SaveParticle)
		.def("SetImage",			&P2DEdit::SetImage)
		.def("SetGroup",			&P2DEdit::SetGroup)
		.def("AddGroup",			&P2DEdit::AddGroup)
		.def("DeleteGroup",			&P2DEdit::DeleteGroup)
		.def("SetMaxCount",			&P2DEdit::SetMaxCount)
		.def("SetAdditive",			&P2DEdit::SetAdditive)
		.def("SetLockRect",			&P2DEdit::SetLockRect)
		.def("SetFuzzyBirth",		&P2DEdit::SetFuzzyBirth)
		.def("SetSizeFromMin",		&P2DEdit::SetSizeFromMin)
		.def("SetSizeFromMax",		&P2DEdit::SetSizeFromMax)
		.def("SetSizeToMin",		&P2DEdit::SetSizeToMin)
		.def("SetSizeToMax",		&P2DEdit::SetSizeToMax)
		.def("SetLifespan",			&P2DEdit::SetLifespan)
		.def("SetMinSpeed",			&P2DEdit::SetMinSpeed)
		.def("SetMaxSpeed",			&P2DEdit::SetMaxSpeed)
		.def("SetStretchSpeed",		&P2DEdit::SetStretchSpeed)
		.def("SetMinSpeedMag",		&P2DEdit::SetMinSpeedMag)
		.def("SetGenRate",			&P2DEdit::SetGenRate)
		.def("AddColor",			&P2DEdit::AddColor)
		.def("ClearColors",			&P2DEdit::ClearColors)
		.def("UpdatePreviewPos",	&P2DEdit::UpdatePreviewPos)
		.def("TogglePreviewMode",	&P2DEdit::TogglePreviewMode)
	];

	luabind::module(L)
    [
	 luabind::def("GetP2DEdit", GetP2DEdit , luabind::detail::null_type())
	
	]; 
   
	
#endif //_ENABLE_LUABIND
}

void P2DEdit::LoadParticle(const std::string& File)
{
	if (m_pContainer) {
		m_pContainer->SetCmd(P2DEdit_Container::CMD_LOAD, File);
		RefreshUI();
	}
}

void P2DEdit::SaveParticle(const std::string& File)
{
	if (m_pContainer) {
		m_pContainer->SetCmd(P2DEdit_Container::CMD_SAVE, File);
		RefreshUI();
	}
}

void P2DEdit::SetImage(const std::string& Sprite)
{
	if (m_pContainer) m_pContainer->SetCmd(P2DEdit_Container::CMD_IMAGE, Sprite);
}

void P2DEdit::SetGroup(int Group)
{
	if (m_pContainer) {
		P2DEdit_Container::CONTAINER_VAL Data;
		Data.iData = Group;
		m_pContainer->SetCmd(P2DEdit_Container::CMD_GROUP, Data);
		RefreshUI();
	}
}

int P2DEdit::AddGroup()
{
	if (m_pContainer) {
		return m_pContainer->SetCmd(P2DEdit_Container::CMD_ADDGROUP);
	}

	return 0;
}

int P2DEdit::DeleteGroup()
{
	if (m_pContainer) {
		return m_pContainer->SetCmd(P2DEdit_Container::CMD_DELGROUP);
	}

	return 0;
}

void P2DEdit::SetMaxCount(float f)
{
	if (m_pContainer) {
		P2DEdit_Container::CONTAINER_VAL val;

		UTIL_CLAMP(f, 0.0f, 1.0f);

		if (m_PreviewMode == PREVIEW_TRIGGER)
		{
			m_pContainer->GetTriggerC() = int(MinTriggerCount() + f * float(MaxTriggerCount() - MinTriggerCount()));
		}
		else
		{
			val.iData = MinCount() + int(f * float(MaxCount() - MinCount()));
			m_pContainer->SetCmd(P2DEdit_Container::CMD_MAXC, val);
		}
	}
}

void P2DEdit::SetAdditive(bool b)
{
	if (m_pContainer)
		m_pContainer->SetCmd(P2DEdit_Container::CMD_ADDITIVE, b);
}

void P2DEdit::SetLockRect(bool b)
{
	if (m_pContainer)
		m_pContainer->SetCmd(P2DEdit_Container::CMD_LOCKRECT, b);
}

void P2DEdit::SetFuzzyBirth(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		ClampV(v);
		m_pContainer->SetCmd(P2DEdit_Container::CMD_FUZZYBIRTH, v);
	}
}

void P2DEdit::SetSizeFromMin(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		v *= MaxSize();
		m_pContainer->SetCmd(P2DEdit_Container::CMD_SIZEFROM_MIN, v);
	}
}

void P2DEdit::SetSizeFromMax(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		v *= MaxSize();
		m_pContainer->SetCmd(P2DEdit_Container::CMD_SIZEFROM_MAX, v);
	}
}

void P2DEdit::SetSizeToMin(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		v *= MaxSize();
		m_pContainer->SetCmd(P2DEdit_Container::CMD_SIZETO_MIN, v);
	}
}

void P2DEdit::SetSizeToMax(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		v *= MaxSize();
		m_pContainer->SetCmd(P2DEdit_Container::CMD_SIZETO_MAX, v);
	}
}

void P2DEdit::SetLifespan(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		v *= MaxLife();
		m_pContainer->SetCmd(P2DEdit_Container::CMD_LIFESPAN, v);
	}
}

void P2DEdit::SetMinSpeed(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		ClampV(v);
		m_pContainer->SetCmd(P2DEdit_Container::CMD_MINSPEED, v);
	}
}

void P2DEdit::SetMaxSpeed(float x, float y)
{
	if (m_pContainer) {
		math::Vec2 v(x, y);
		ClampV(v);
		m_pContainer->SetCmd(P2DEdit_Container::CMD_MAXSPEED, v);
	}
}

void P2DEdit::SetStretchSpeed(float f)
{
	if (m_pContainer) {
		P2DEdit_Container::CONTAINER_VAL val;
		val.fData = f;
		m_pContainer->SetCmd(P2DEdit_Container::CMD_STRETCHSPEED, val);
	}
}

void P2DEdit::SetMinSpeedMag(float f)
{
	if (m_pContainer) {
		P2DEdit_Container::CONTAINER_VAL val;
		val.fData = (f > 0.0f) ? f : -1.0f;
		m_pContainer->SetCmd(P2DEdit_Container::CMD_MINSPEEDMAG, val);
	}
}

void P2DEdit::SetGenRate(float f)
{
	if (m_pContainer) {
		P2DEdit_Container::CONTAINER_VAL val;
		val.fData = (f > 0.0f) ? (1.0f / (f * MaxFreq())) : 1.0f;
		m_pContainer->SetCmd(P2DEdit_Container::CMD_GENRATE, val);
	}
}

void P2DEdit::AddColor(float r, float g, float b, float a)
{
	if (m_pContainer)
		m_pContainer->SetCmd(P2DEdit_Container::CMD_ADDCOLOR, math::Vec4(r, g, b, a));
}

void P2DEdit::ClearColors()
{
	if (m_pContainer)
		m_pContainer->SetCmd(P2DEdit_Container::CMD_CLEARCOLOR);
}

void P2DEdit::ClampV(math::Vec2& v)
{
	UTIL_CLAMP(v.x, 0.0f, 1.0f);
	UTIL_CLAMP(v.y, 0.0f, 1.0f);

	v.x = MinV() + (v.x * (MaxV() - MinV()));
	v.y = MinV() + (v.y * (MaxV() - MinV()));
}

void P2DEdit::ExpandV(math::Vec2& v)
{
	UTIL_CLAMP(v.x, MinV(), MaxV());
	UTIL_CLAMP(v.y, MinV(), MaxV());

	v.x = (v.x - MinV()) / (MaxV() - MinV());
	v.y = (v.y - MinV()) / (MaxV() - MinV());
}

void P2DEdit::UpdatePreviewPos()
{
	if (m_pContainer && m_pPanel && !m_Widgets.PreviewPane.empty())
	{
		if (ui::UIWidget* pPreviewPane = m_pPanel->GetWidgetByName(m_Widgets.PreviewPane))
		{
			math::Vec2 Offset = pPreviewPane->GetPosition() + (0.5f * pPreviewPane->GetSize());
			m_pContainer->GetOffset() = GET_MOUSE().GetPos() - Offset;
		}
	}
}

void P2DEdit::TogglePreviewMode()
{
	m_PreviewMode = PREVIEW_MODE(int(m_PreviewMode+1) % int(PREVIEW_COUNT));
	RefreshUI();
}
